<?php

define ("__LOAD_FROM_FILE", 0);
define ("__LOAD_FROM_MEM", 1);

class TDomXMLParser{

#----------------------------------------------------------------------------------------------------------------------

	public $convert 	= false; #if true convert from UTF-8 to WINDOWS-1251
	public $strtoupper	= false;

	private $stack		= array();
	private $error		= '';
	private $xmlh		= null;
	private $value		= "";

#----------------------------------------------------------------------------------------------------------------------

	function __construct(){
		$this->xmlh = xml_parser_create();
		if ( $this->xmlh ){
			xml_set_object( $this->xmlh, $this );
			xml_parser_set_option($this->xmlh, XML_OPTION_CASE_FOLDING, false);
			xml_set_element_handler( $this->xmlh, "bTag", "eTag" );
			xml_set_character_data_handler( $this->xmlh, "cdata" );
		}else
		    $this->error = "Can't create xml reference";
	}

#----------------------------------------------------------------------------------------------------------------------

	function __destruct(){
		if ( $this->xmlh ){
			xml_parser_free($this->xmlh);
		}
	}

#----------------------------------------------------------------------------------------------------------------------

	public function Parse( $value, $mode = __LOAD_FROM_FILE ){
		if ( $this->convert && !function_exists('iconv')){
			$this->error = "Can't found iconv() function. Install PHP with iconv extension";
		}else{
			if ( $mode == __LOAD_FROM_FILE ){
				if ( file_exists($value) ){
					$xml_src = file_get_contents($value);
				}else
				    $this->error = "Can't open XML file: ".$value;
			}else
			    $xml_src = $value;

			if ( !$this->error ){
				if ( $this->convert ){
					$xml_src = eregi_replace('encoding="WINDOWS-1251"', 'encoding="UTF-8"', $xml_src);
					$xml_src = @iconv('WINDOWS-1251', 'UTF-8', $xml_src);
				}
				$data = xml_parse( $this->xmlh, $xml_src );
				if( !$data ){
				   $this->error = sprintf("XML error: %s at line %d",
						xml_error_string(xml_get_error_code($this->xmlh)),
						xml_get_current_line_number($this->xmlh));
				}
			}
			unset($xml_src);
		}
		if ( $this->error ) exit( $this->error );
		return $this->stack;
	}

#----------------------------------------------------------------------------------------------------------------------

	public function Free(){
	 	unset( $this );
	}

#----------------------------------------------------------------------------------------------------------------------

	private function bTag( $parser, $name, $attrs ){
		$rname 	= $name;
		$rattrs = $attrs;
		$this->value = "";

		if ( $this->strtoupper ){
			$rname 	= strtoupper($rname);
			$rattrs = array_change_key_case($rattrs, CASE_UPPER);
		}

		#convert tag name data
		if ( $this->convert ){
			$rname 	= @iconv('UTF-8', 'WINDOWS-1251', $rname);
		}

		if ( !empty( $rattrs ) ){
			#convert attributes data
			if ( $this->convert ){
				$buf = $rattrs;
				unset($rattrs);
				$keys = array_keys($buf);
				$index = sizeof($keys);
				for($i=0; $i<$index; $i++){
					$key = @iconv('UTF-8', 'WINDOWS-1251', $keys[$i]);
					$val = @iconv('UTF-8', 'WINDOWS-1251', $buf[$keys[$i]]);
					if ( $key && $val ){
						$rattrs[$key] = $val;
					}
				}
			}
			$tag = array( "tag" => $rname, "attributes" => $rattrs );
		}else{
			$tag = array( "tag" => $rname );
		}
		array_push( $this->stack, $tag );
		unset($rattrs);
	}

#----------------------------------------------------------------------------------------------------------------------

	private function cdata( $parser, $cdata ){
		$buf = $cdata;

		if ( $this->convert ){
			$buf = @iconv('UTF-8', 'WINDOWS-1251', $buf);
		}
		if( $buf ){
			$index = sizeof($this->stack);
			if ( $index > 0 ){
				$this->value .= $buf;
			}
		}
		unset($buf);
	}

#----------------------------------------------------------------------------------------------------------------------

	private function eTag( $parser, $name ){
		$index = sizeof($this->stack);
		if ( $index > 1 ){
			$this->stack[$index-1]['value'] = trim($this->value);
			$this->stack[$index-2]['children'][] = $this->stack[$index-1];
			array_pop($this->stack);
		}
	}

#----------------------------------------------------------------------------------------------------------------------

}#end class

?>